package com.wm.blog_admin.service;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wm.blog_admin.dao.*;
import com.wm.blog_admin.query.TRoleQuery;
import com.wm.blog_common.base.BeanUtils;
import com.wm.blog_common.bean.PageHelper;
import com.wm.blog_common.bean.QueryPage;
import com.wm.blog_common.constatnt.ErrorConstant;
import com.wm.blog_common.domain.TRoleDO;
import com.wm.blog_common.entity.*;
import com.wm.blog_common.enums.DeleteFlag;
import com.wm.blog_common.exception.BusinessException;
import com.wm.blog_common.resp.IviewTreeResp;
import com.wm.blog_common.result.Result;
import com.wm.blog_common.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 半卷流年
 * @since 2020-03-24
 */
@Service
public class TRoleService {
    @Autowired
    private TRoleDAO tRoleDAO;

    @Autowired
    private TRoleMenuDAO tRoleMenuDAO;

    @Autowired
    private TMenuDAO tMenuDAO;

    @Autowired
    private TAdminRoleDAO tAdminRoleDAO;

    @Autowired
    private TAdminDAO tAdminDAO;

    /**
     * 根据ID查询
     *
     * @param id
     * @return
     */
    public Result<TRoleDO> selectById(Long id) {
        return Result.success(BeanUtils.copyProperties(tRoleDAO.getById(id), TRoleDO.class));
    }

    /**
     * 根据ID删除
     *
     * @param id
     * @return
     */
    public Result deleteById(Long id) {
        return tRoleDAO.removeById(id) ? Result.success() : Result.failure();
    }

    /**
     * 添加
     *
     * @param tRole
     * @return
     */
    public Result insert(TRole tRole) {
        return tRoleDAO.save(tRole) ? Result.success() : Result.failure();
    }

    /**
     * 修改
     *
     * @param tRole
     * @return
     */
    public Result update(TRole tRole) {
        return tRoleDAO.updateById(tRole) ? Result.success() : Result.failure();
    }

    /**
     * 统计总数
     *
     * @param query
     * @return
     */
    public Result<Integer> count(TRoleQuery query) {
        return Result.success(tRoleDAO.count(this.combineQuery(query)));
    }


    /**
     * 分页查询
     *
     * @param page
     * @return
     */
    public Result<Page<TRoleDO>> page(QueryPage page, TRoleQuery query) {
        if (StringUtil.isNotEmpty(query.getCreator())) {
            QueryWrapper<TAdmin> wrapper = new QueryWrapper<>();
            wrapper.like("user_name", query.getCreator());
            List<Long> list = Optional
                    .ofNullable(tAdminDAO.list(wrapper))
                    .orElse(Collections.emptyList())
                    .stream()
                    .map(TAdmin::getId)
                    .distinct()
                    .collect(Collectors.toList());
            if(CollectionUtils.isEmpty(list)){
                //防止出现空集合
                list.add(-1L);
            }
            query.setCreatorIdList(list);
        }
        if (StringUtil.isNotEmpty(query.getEditor())) {
            QueryWrapper<TAdmin> wrapper = new QueryWrapper<>();
            wrapper.like("user_name", query.getEditor());
            List<Long> list = Optional
                    .ofNullable(tAdminDAO.list(wrapper))
                    .orElse(Collections.emptyList())
                    .stream()
                    .map(TAdmin::getId)
                    .distinct()
                    .collect(Collectors.toList());
            if(CollectionUtils.isEmpty(list)){
                //防止出现空集合
                list.add(-1L);
            }
            query.setEditorIdList(list);
        }
        Page<TRoleDO> iPage = PageHelper.newPage(tRoleDAO.page(page, this.combineQuery(query)), TRoleDO.class);
        if (!CollectionUtils.isEmpty(iPage.getRecords())) {
            List<Long> idList = new ArrayList<>();
            iPage.getRecords().forEach(x -> {
                idList.add(x.getCreator());
                idList.add(x.getEditor());
            });
            List<Long> list = idList
                    .stream()
                    .distinct()
                    .collect(Collectors.toList());
            //构建id map   k:id,value:name
            Map<Long, String> map = Optional
                    .ofNullable(tAdminDAO.listByIds(list))
                    .orElse(Collections.emptyList())
                    .stream()
                    .collect(Collectors.toMap(TAdmin::getId, TAdmin::getUserName));
            List<TRoleDO> resultList = iPage.getRecords()
                    .stream()
                    .peek(x -> {
                        x.setCreateName(map.getOrDefault(x.getCreator(), null));
                        x.setEditorName(map.getOrDefault(x.getEditor(), null));
                    })
                    .collect(Collectors.toList());
            iPage.setRecords(resultList);
        }
        return Result.success(iPage);
    }

    /**
     * 组装查询条件
     *
     * @param query
     * @return
     */
    private QueryWrapper<TRole> combineQuery(TRoleQuery query) {
        QueryWrapper<TRole> wrapper = new QueryWrapper<>();
        Optional.ofNullable(query).ifPresent(item -> {
            Optional.ofNullable(query.getStatus()).ifPresent(x -> {
                wrapper.eq("status", x);
            });
            Optional.ofNullable(query.getRoleName()).filter(StringUtil::isNotEmpty).ifPresent(x -> {
                wrapper.like("role_name", x);
            });
            Optional.ofNullable(query.getCreator()).filter(StringUtil::isNotEmpty).ifPresent(x -> {
                wrapper.in("creator", query.getCreatorIdList());
            });
            Optional.ofNullable(query.getEditor()).filter(StringUtil::isNotEmpty).ifPresent(x -> {
                wrapper.in("editor", query.getEditorIdList());
            });
        });
        return wrapper;
    }


    /**
     * 权限设置,关联菜单权限和角色的关系
     *
     * @param query
     * @return
     */
    public Result bindMenu(TRoleQuery query) {
        query = Optional.ofNullable(query).orElse(new TRoleQuery());
        if (ObjectUtils.isEmpty(query.getRoleId())) {
            return Result.failure("角色id为空");
        }
        //删除该角色下的所有权限
        QueryWrapper<TRoleMenu> roleMenuQueryWrapper = new QueryWrapper<>();
        roleMenuQueryWrapper.eq("role_id", query.getRoleId());
        tRoleMenuDAO.remove(roleMenuQueryWrapper);
        final Long roleId = query.getRoleId();
        //重新赋予新的菜单权限
        if (!CollectionUtils.isEmpty(query.getMenuList())) {
            List<Long> menuIdList = query.getMenuList()
                    .stream()
                    .map(MenuTree::getId)
                    .collect(Collectors.toList());
            //需要处理父级菜单下子菜单没有全部勾选的情况下,父级菜单的id不能丢失
            //查询所有菜单的父级id
            List<Long> parentIdList = Optional
                    .ofNullable(tMenuDAO.listByIds(menuIdList))
                    .orElse(Collections.emptyList())
                    .stream()
                    .map(TMenu::getParentId)
                    .filter(x -> -1 != x)
                    .distinct()
                    .collect(Collectors.toList());
            //如果前端传入的Id没有命中父级id,需要将父级id也加入到当前菜单id中去,防止丢失
            parentIdList.removeAll(menuIdList);
            if (!CollectionUtils.isEmpty(parentIdList)) {
                menuIdList.addAll(parentIdList);
            }
            List<TRoleMenu> list = menuIdList
                    .stream()
                    .map(x -> {
                        TRoleMenu roleMenu = new TRoleMenu();
                        roleMenu.setMenuId(x);
                        roleMenu.setRoleId(roleId);
                        return roleMenu;
                    })
                    .collect(Collectors.toList());
            tRoleMenuDAO.saveBatch(list);
        }
        return Result.success();
    }


    /**
     * 根据角色查询菜单
     *
     * @param query
     * @return
     */
    public Result roleMenu(TRoleQuery query) {
        query = Optional.ofNullable(query).orElse(new TRoleQuery());
        if (ObjectUtils.isEmpty(query.getRoleId())) {
            return Result.failure(ErrorConstant.ROLE_ID_EMPTY);
        }
        //查询该角色下所有的权限菜单
        QueryWrapper<TRoleMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("role_id", query.getRoleId());
        List<Long> menuIdList = Optional
                .ofNullable(tRoleMenuDAO.list(wrapper))
                .orElse(Collections.emptyList())
                .stream()
                .map(TRoleMenu::getMenuId)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(menuIdList)) {
            //查询权限菜单
            List<TMenu> menuList = (List<TMenu>) Optional.ofNullable(tMenuDAO.listByIds(menuIdList)).orElse(Collections.emptyList());
            //构建菜单树,供iview前端格式使用
            List<MenuTree> treeList = MenuUtil.buildDeepTree(menuList);
            //转成iview树形控件格式
            List<IviewTreeResp> list = new ArrayList<>();
            CommonUtil.buildIvTree(treeList, list);
            return Result.success(list);
        }
        return Result.success();
    }

    /**
     * 列表查询
     *
     * @param query
     * @return
     */
    public Result list(TRoleQuery query) {
        query = Optional.ofNullable(query).orElse(new TRoleQuery());
        Optional.ofNullable(query.getUserId()).orElseThrow(() -> new BusinessException(ErrorConstant.USER_ID_EMPTY));
        query.setDelFlag(DeleteFlag.ENABLE.getValue());
        QueryWrapper<TRole> wrapper = this.combineQuery(query);
        List<TRole> roleList = Optional.ofNullable(tRoleDAO.list(wrapper)).orElse(Collections.emptyList());
        List<TRoleDO> doList = Optional.ofNullable(BeanUtils.copyListProperties(roleList, TRoleDO.class)).orElse(Collections.emptyList());
        //查询该用户拥有的角色id
        QueryWrapper<TAdminRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("admin_id", query.getUserId());
        List<Long> roleIdList = Optional
                .ofNullable(tAdminRoleDAO.list(queryWrapper))
                .orElse(Collections.emptyList())
                .stream()
                .map(TAdminRole::getRoleId)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(roleIdList)) {
            //设置是否选中
            List<TRoleDO> resultList = doList.stream().peek(y -> {
                if (roleIdList.contains(y.getId())) {
                    y.set_checked(true);
                }
            }).collect(Collectors.toList());
            return Result.success(resultList);
        }
        return Result.success(doList);
    }


    public Result saveOrUpdate(TRoleQuery query) {
        Optional.ofNullable(query.getRoleName()).orElseThrow(() -> new BusinessException(ErrorConstant.ROLE_NAME_EMPTY));
        TRole role = new TRole();
        BeanUtils.copyProperties(query, role);
        if (ObjectUtils.isEmpty(query.getId())) {
            if (this.checkByName(query.getRoleName())) {
                return Result.failure(ErrorConstant.ROLE_NAME_EXSIT);
            }
            //新增
            role.setStatus(DeleteFlag.ENABLE.getValue());
            return tRoleDAO.save(role) ? Result.success() : Result.failure();
        } else {
            //修改
            return tRoleDAO.updateById(role) ? Result.success() : Result.failure();
        }
    }

    /**
     * 校验角色名称是否存在  存在返回true 不存在返回false
     *
     * @param roleName
     * @return
     */
    private boolean checkByName(String roleName) {
        if (StringUtils.isEmpty(roleName)) {
            return true;
        }
        QueryWrapper<TRole> wrapper = new QueryWrapper<>();
        wrapper.eq("role_name", roleName);
        wrapper.last("limit 1");
        TRole role = Optional.ofNullable(tRoleDAO.getOne(wrapper)).orElse(new TRole());
        return !ObjectUtils.isEmpty(role.getId());
    }


    public Result roleList() {
        QueryWrapper<TRole> wrapper = new QueryWrapper<>();
        wrapper.eq("status",DeleteFlag.ENABLE.getValue());
        return Result.success(Optional.ofNullable(tRoleDAO.list(wrapper)).orElse(Collections.emptyList()));
    }
}







